package cn.skyquant.quant4j.api.quant;

import cn.skyquant.quant4j.api.enums.TitansType;
import cn.skyquant.quant4j.sdk.enums.TradeDirection;
import cn.skyquant.quant4j.sdk.util.time.CalendarUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class TimeBar extends Bar {
    public final long time;

    public TimeBar(double open, double close, double high, double low, double volumn, long time) {
        super(open, close, high, low, volumn);
        this.time = time;
    }

    public static boolean isV1(List<TimeBar> barList, int i,int v_days){
        int half_v_days = v_days/2 ;
        if(i<half_v_days || i>barList.size()-(half_v_days+1)){
            return false;
        }
        List<TimeBar> beforeList = new ArrayList<>();
        List<TimeBar> afterList = new ArrayList<>();
        for(int j=half_v_days;j>=1;j--){
            beforeList.add(barList.get(i-j));
        }
        TimeBar m = barList.get(i);
        for(int j=1;j<=half_v_days;j++){
            afterList.add(barList.get(i+j));
        }
        Bar before = Bar.merge(beforeList);
        Bar after = Bar.merge(afterList);
        if( m.low < before.low && m.low < after.low //c必须是n天K线中最低的
                && (after.close > m.close && after.high > m.high) //de中high和close都大于c
                && (before.open > before.close )  //a,b中必须有有一根阴柱，且
        ){
            return true;
        }
        return false;
    }

    public static boolean isV2(List<TimeBar> barList, int i,int v_days){
        int half_v_days = v_days/2 ;
        if(i<half_v_days || i>barList.size()-(half_v_days+1)){
            return false;
        }
        List<TimeBar> beforeList = new ArrayList<>();
        List<TimeBar> afterList = new ArrayList<>();
        for(int j=half_v_days;j>=1;j--){
            beforeList.add(barList.get(i-j));
        }
        TimeBar m = barList.get(i);
        for(int j=1;j<=half_v_days;j++){
            afterList.add(barList.get(i+j));
        }
        Bar before = Bar.merge(beforeList);
        Bar after = Bar.merge(afterList);
        if( m.low < before.low && m.low < after.low //c的low必须是n天K线中最低的
//                && (after.close > m.open && after.high > m.high) //after中和close都大于c
//                && (before.open > before.close && before.high > m.high)  //before必须是阴柱,before的high也比m的high高
        ){
            return true;
        }
        return false;
    }

    public static boolean isRV1(List<TimeBar> barList,int i,int v_days){
        int half_v_days = v_days/2 ;
        if(i<half_v_days || i>barList.size()-(half_v_days+1)){
            return false;
        }
        List<TimeBar> beforeList = new ArrayList<>();
        List<TimeBar> afterList = new ArrayList<>();
        for(int j=half_v_days;j>=1;j--){
            beforeList.add(barList.get(i-j));
        }
        TimeBar m = barList.get(i);
        for(int j=1;j<=half_v_days;j++){
            afterList.add(barList.get(i+j));
        }
        Bar before = Bar.merge(beforeList);
        Bar after = Bar.merge(afterList);
        if( m.high > before.high && m.high > after.high //c必须是五天K线中最高的
                && (after.close < m.close && after.low < m.low) //d,e中必须有一天low和close都小于c
                && (before.open < before.close )  //ab必须为阳柱，且low必须必c小
        ){
            return true;
        }
        return false;
    }

    public static boolean isRV2(List<TimeBar> barList,int i,int v_days){
        int half_v_days = v_days/2 ;
        if(i<half_v_days || i>barList.size()-(half_v_days+1)){
            return false;
        }
        List<TimeBar> beforeList = new ArrayList<>();
        List<TimeBar> afterList = new ArrayList<>();
        for(int j=half_v_days;j>=1;j--){
            beforeList.add(barList.get(i-j));
        }
        TimeBar m = barList.get(i);
        for(int j=1;j<=half_v_days;j++){
            afterList.add(barList.get(i+j));
        }
        Bar before = Bar.merge(beforeList);
        Bar after = Bar.merge(afterList);
        if( m.high > before.high && m.high > after.high
//                && (after.close < m.open && after.low < m.low)
////                && (before.open < before.close && before.low < m.low)
        ){
            return true;
        }
        return false;
    }

    public static TitansValue getTitans(TitansType titansType,int k, double r,  List<TimeBar> timeBarList, int i){
        if(i<k){
            return null;
        }
        //第一步，计算平均柱体的长度
        double avg_bar = 0;
        for(int j=1;j<=k;j++){
            TimeBar timeBar = timeBarList.get(i-j);
            avg_bar += titansType==TitansType.HL?Math.abs(timeBar.high - timeBar.low):Math.abs(timeBar.close - timeBar.open);
        }
        avg_bar /= k;
        //第二步，往前递归查找，直到找到合并柱体的长度大于平均的长度
        MergeBar mergeBar = null;
        List<TimeBar> subTimeBarList;
        for(int j=i-1;j>=0;j--){
            subTimeBarList = timeBarList.subList(j,i);
            mergeBar = MergeBar.mergeBar(subTimeBarList);
            double k_bar = titansType==TitansType.HL?Math.abs(mergeBar.high - mergeBar.low):Math.abs(mergeBar.close - mergeBar.open);
            if(k_bar>avg_bar * (1+subTimeBarList.size()*r)){
                break;
            }
        }
        if(mergeBar==null){
            return null;
        }

        TradeDirection tradeDirection = null ;
        int level = 1;

        if(mergeBar.open < mergeBar.close){
            tradeDirection = TradeDirection.LONG;
            level += 1;
        }else {
            tradeDirection = TradeDirection.SHORT;
            level += 1;
        }
        return new TitansValue(k,r,tradeDirection,level,mergeBar,avg_bar);
    }

    public static TitansValue getLastTitans(TitansType titansType,int k,double r,List<TimeBar> timeBarList){
        return getTitans(titansType,k,r,timeBarList,timeBarList.size()-1);
    }

    public static double getMinLow(int i_begin, int i_end, List<TimeBar> barList) {
        double min_low = Double.MAX_VALUE;
        for(int i=i_begin;i<=i_end;i++){
            TimeBar bar = barList.get(i);
            if(bar.low<=min_low){
                min_low = bar.low;
            }

        }
        return min_low;
    }

    public static double getMaxHigh(int i_begin, int i_end, List<TimeBar> barList) {
        double max_high = 0;
        for(int i=i_begin;i<=i_end;i++){
            TimeBar bar = barList.get(i);
            if(bar.high>=max_high){
                max_high = bar.high;
            }

        }
        return max_high;
    }

    public Object[] getObj(){
        return new Object[]{CalendarUtils.formatGMTSimple(time),open,close,high,low,volumn};
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof TimeBar)) return false;
        TimeBar timeBar = (TimeBar) o;
        return time == timeBar.time;
    }

    @Override
    public int hashCode() {
        return Objects.hash(time);
    }


    @Override
    public String toString() {
        return String.format("[%s,o=%s,c=%s,h=%s,l=%s,v=%s]",CalendarUtils.formatGMTStandard(time) ,open, close, high, low, volumn);
    }
}
